
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include <input_manager.h>

static PInputDevice g_InputDevs  = NULL;  //定义的链表头
//要想访问这些缓存区要上个-锁（宝库13），有3项代码会访问（屏、网络、上层应用）
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;


/* 6、  start of 实现环形buffer */
#define BUFFER_LEN 20   /*指buffer的长度，自定义为20*/
static int g_iRead  = 0;  //读和写的指针
static int g_iWrite = 0;
static InputEvent g_atInputEvents[BUFFER_LEN];
//6.3 判断是空是满
static int isInputBufferFull(void) //
{
	return (g_iRead == ((g_iWrite + 1) % BUFFER_LEN));//下一个写的位置等于读的位置的话，表示满。他画了个图有讲
}
static int isInputBufferEmpty(void)
{
	return (g_iRead == g_iWrite); //读写位置相等的话就表示为空
}
//6.1 存放数据到buffer
static void PutInputEventToBuffer(PInputEvent ptInputEvent)
{
	if (!isInputBufferFull())
	{
		g_atInputEvents[g_iWrite] = *ptInputEvent;
		g_iWrite = (g_iWrite + 1) % BUFFER_LEN;
	}
}
//6.2 获得数据
static int GetInputEventFromBuffer(PInputEvent ptInputEvent)
{
	if (!isInputBufferEmpty()) //不满的话执行下面的
	{
		*ptInputEvent = g_atInputEvents[g_iRead];
		g_iRead = (g_iRead + 1) % BUFFER_LEN;
		return 1;
	}
	else
	{
		return 0;
	}
}
/* end of 实现环形buffer */



//4、
void RegisterInputDevice(PInputDevice ptInputDev)
{
	ptInputDev->ptNext = g_InputDevs;
	g_InputDevs = ptInputDev;
}

/* 1、 */
void InputSystemRegister(void)
{
	/* 1.1 regiseter touchscreen */
	extern void TouchscreenRegister(void);
	TouchscreenRegister();

	/* 1.2 regiseter netinput */
	extern void NetInputRegister(void);
	NetInputRegister();
}
//5、线程启动以后，要做的函数
static void *input_recv_thread_func (void *data)
{
	PInputDevice tInputDev = (PInputDevice)data; //(PInputDevice)是强制类型转换
	InputEvent tEvent;
	int ret;
	
	while (1)
	{
		/* 读数据 */
		ret = tInputDev->GetInputEvent(&tEvent); //用它GetInputEvent获取内容，存放到tEvent

		if (!ret)//ret为0表示成功
		{	
			/* 保存数据 */
			pthread_mutex_lock(&g_tMutex); //获得锁后，可独享函数
			PutInputEventToBuffer(&tEvent);//将数据保存到环形缓冲区中
			/* 唤醒等待数据的线程 */
			pthread_cond_signal(&g_tConVar);/* 通知接收线程 */	
			pthread_mutex_unlock(&g_tMutex);//唤醒以后，释放锁，让别人可以访问
		}
	}

	return NULL;
}

//2、链表中已经建好了两个设备，需把每个设备中的链表取出来，调用函数初始化硬件，为没饿设备创造线程
void IntpuDeviceInit(void)
{
	int ret;
	pthread_t tid;
	
	/* for each inputdevice, init, pthread_create（创建线程） */
	PInputDevice ptTmp = g_InputDevs;
	while (ptTmp)
	{
		/* init device */
		ret = ptTmp->DeviceInit();

		/* pthread create */
		if (!ret)
		{
			ret = pthread_create(&tid, NULL, input_recv_thread_func, ptTmp);
		}

		ptTmp= ptTmp->ptNext;
	}
}

//3、上层代码调用它，得到数据，无数据则休眠
int GetInputEvent(PInputEvent ptInputEvent)
{
	InputEvent tEvent;
	int ret;
	/* 无数据则休眠 */
	pthread_mutex_lock(&g_tMutex);
	//如果成功获得了数据的话（执行GetInputEventFromBuffer），释放锁（g_tMutex），否则休眠等待
	if (GetInputEventFromBuffer(&tEvent))
	{
		pthread_mutex_unlock(&g_tMutex); //释放
		return 0;
	}
	else
	{
		/* 休眠等待 */
		pthread_cond_wait(&g_tConVar, &g_tMutex);	
		//等待的时候再去尝试获得数据
		if (GetInputEventFromBuffer(&tEvent))
		{
			ret = 0;
		}
		else
		{
			ret = -1;
		}
		pthread_mutex_unlock(&g_tMutex);		
	}
	return ret;
	/* 返回数据 */
}



